package com.iuie.ns.system.service.code.impl;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.github.pagehelper.PageHelper;
import com.iuie.ns.frame.exception.ServiceException;
import com.iuie.ns.frame.persistence.dao.IGenericDao;
import com.iuie.ns.frame.persistence.dao.IGenericDao.MatchType;
import com.iuie.ns.frame.service.impl.BaseServiceImpl;
import com.iuie.ns.frame.utils.BeanUtils;
import com.iuie.ns.frame.utils.ListUtils;
import com.iuie.ns.frame.utils.StringUtils;
import com.iuie.ns.frame.utils.beans.UserOperateVO;
import com.iuie.ns.frame.web.dataset.vo.Page;
import com.iuie.ns.system.dao.code.ISysCodeInfoDao;
import com.iuie.ns.system.factory.BatchBuildeObjectFactory;
import com.iuie.ns.system.maker.BatchMaker;
import com.iuie.ns.system.mapper.code.SysCodeInfoMapper;
import com.iuie.ns.system.service.code.ISysCodeInfoService;
import com.iuie.ns.system.service.code.ISysCodeTypeService;
import com.iuie.ns.system.tags.beans.SysDropCodeTypeVO;
import com.iuie.ns.system.vo.code.SysCodeInfoVO;
import com.iuie.ns.system.vo.code.SysCodeTypeVO;

@Service("codeInfoService")
public class SysCodeInfoServiceImpl extends BaseServiceImpl<SysCodeInfoVO> implements ISysCodeInfoService {

	@Resource
	private ISysCodeInfoDao codeInfoDao;
	
	@Resource
	private SysCodeInfoMapper codeInfoMapper;
	
	@Resource
	private ISysCodeTypeService codeTypeService;
	
	@Resource
	private BatchBuildeObjectFactory batchObjectFactory;
	
	@Override
	public List<SysCodeInfoVO> findByCodeTypeId(String codeTypeId, Integer state) {
		List<SysCodeInfoVO> list = codeInfoMapper.findByCodeTypeId(codeTypeId, state);
		return list;
	}

	@Override
	public List<SysCodeInfoVO> findByCodeName(String codeName) {
		SysCodeInfoVO codeInfo = new SysCodeInfoVO();
		codeInfo.setCodeInfoName(codeName);
		Map<String, MatchType> conditions = new HashMap<String, IGenericDao.MatchType>();
		conditions.put("codeInfoName", MatchType.MATCH_LIKE);
		List<SysCodeInfoVO> list = codeInfoDao.findAll(codeInfo,conditions);
		return list;
	}

	@Override
	protected IGenericDao<SysCodeInfoVO, Serializable> getGenericDao() {
		return codeInfoDao;
	}

	@Override
	public String findMaxCodeValue(String type) {
	    return codeInfoDao.findMaxCodeValue(type);
	}

	@Override
	public List<SysDropCodeTypeVO> findCodeInfosByTypeIdArray(Set<String> typeIds) {
		List<SysDropCodeTypeVO> list = codeInfoMapper.findCodeInfosByTypeIdArray(typeIds);
		return list;
	}

    @Override
    public void deleteById(String id) {
        codeInfoDao.deleteById(id);
    }

    @Override
    public void saveTreeCodeInfo(UserOperateVO oper, String codeTypeId) throws Exception {
        List<SysCodeInfoVO> newRecords = BeanUtils.mapsToObjects(oper.getNewRecords(), SysCodeInfoVO.class);
        List<SysCodeInfoVO> updateRecords = BeanUtils.mapsToObjects(oper.getUpdateRecords(), SysCodeInfoVO.class);
        List<SysCodeInfoVO> deleteRecords = BeanUtils.mapsToObjects(oper.getDeleteRecords(), SysCodeInfoVO.class);
        if (ListUtils.isNotEmpty(newRecords)) {
            this.batchAdd(newRecords, codeTypeId);
        }
        if (ListUtils.isNotEmpty(updateRecords)) {
            this.batchUpdate(updateRecords);
        }
        if (ListUtils.isNotEmpty(deleteRecords)) {
            this.batchDelete(deleteRecords);
        }
    }

    @Override
    public String getNewCodeValue(String codeTypeId, Integer x) {
        String codeValue = this.findMaxCodeValue(codeTypeId);
        if (codeValue != null) {
            int intV =  Integer.parseInt(codeValue);
            String ov = String.valueOf(intV + 1 + x);
            StringBuilder sb = new StringBuilder("000000");
            for (int i = (6 - ov.length()); i < 6; i++) {
                sb.setCharAt(i, ov.charAt(i + ov.length() - 6));
            }
           return sb.toString();
        } else {
            return "000001";
        }
    }
    
    @Override
    public void editCodeInfo(SysCodeInfoVO codeInfo) {
        if (StringUtils.isEmpty(codeInfo.getCodeInfoValue())) {
            String codeTypeId = codeInfo.getCodeType().getCodeTypeId();
            String codeInfoValue = this.getNewCodeValue(codeTypeId, 0);
            codeInfo.setCodeInfoValue(codeInfoValue);
        }
        if (StringUtils.isEmpty(codeInfo.getId())) {
            codeInfo.setId(StringUtils.uuid());
            codeInfoDao.save(codeInfo);
            return ;
        }
        codeInfoDao.update(codeInfo);
    }

    @Override
    public void batchAdd(List<SysCodeInfoVO> records, String codeTypeId) {
        // 复制code info value
        Integer i = 0;
        if (ListUtils.isNotEmpty(records)) {
            Iterator<SysCodeInfoVO> it = records.iterator();
            while (it.hasNext()) {
                SysCodeInfoVO code = it.next();
                
                code.setCodeInfoValue(this.getNewCodeValue(codeTypeId, i++));
                
                SysCodeTypeVO codeType = new SysCodeTypeVO();
                codeType.setCodeTypeId(codeTypeId);
                code.setCodeType(codeType);
             }
         }
        codeInfoMapper.batchAdd(records);
    }

    @Override
    public void batchUpdate(List<SysCodeInfoVO> records) {
        codeInfoMapper.batchUpdate(records);
    }

    @Override
    public void batchDelete(List<SysCodeInfoVO> records) {
        codeInfoMapper.batchDelete(records);
    }

    @Override
    public List<SysCodeInfoVO> findCodeInfoByCodeTypeAndCondition(SysCodeInfoVO codeInfo, Page page, String typeId) {
        PageHelper.startPage(page.getPage(), page.getRows(), true);
        List<SysCodeInfoVO> list = codeInfoMapper.findCodeInfoByCodeTypeAndCondition(codeInfo, typeId);
        page.loadData(list);
        return list;
    }

    @Override
    public Integer getCodeInfoCountByTypeId(String typeId) {
        return codeInfoMapper.getCodeInfoCountByTypeId(typeId);
    }

	@Override
	public void removeCodeInfoById(String id) {
		codeInfoMapper.removeById(id);
	}

	@Override
	public void saveCodeInfo(SysCodeInfoVO codeInfo) {
		if (codeInfo == null) {
			throw new ServiceException("保存码值失败，码值信息为空！");
		}
		if (codeInfo.getCodeType() == null) {
			throw new ServiceException("保存码值失败，码值类型不能为空！");
		}
		if (StringUtils.isEmpty(codeInfo.getCodeInfoValue()) || StringUtils.isEmpty(codeInfo.getId())) {
			SysCodeInfoVO history = this.findCodeInfoByCodeValueAndCodeType(codeInfo.getCodeInfoValue(), codeInfo.getCodeType().getCodeTypeId());
			if (history != null) {
				throw new ServiceException("新增码值失败，码值【codeName = " + codeInfo.getCodeInfoValue() + ", codeName" + codeInfo.getCodeInfoName() + "】已存在，请选择更新！");
			}
			// 新增记录
			codeInfo.setId(StringUtils.uuid());
			if (StringUtils.isEmpty(codeInfo.getCodeInfoValue())) {
				codeInfo.setCodeInfoValue(this.getNewCodeValue(codeInfo.getCodeType().getCodeTypeId(), 0));
			}
			codeInfoDao.save(codeInfo);
		} else {
			codeInfoDao.update(codeInfo);
		}
	}

	@Override
	public SysCodeInfoVO findCodeInfoById(String id) {
		return codeInfoMapper.findCodeInfoById(id);
	}

	@Override
	public SysCodeInfoVO findCodeInfoByCodeValueAndCodeType(String codeInfoValue, String codeType) {
		return codeInfoMapper.findCodeInfoByCodeValueAndCodeType(codeInfoValue, codeType);
	}
	
	@Override
	public void batchSaveCodeInfo(String text, String rule, String typeId) {
		if (StringUtils.isBlank(text)) {
			throw new ServiceException("保存失败，text内容为空！");
		}
		SysCodeInfoVO codeInfo = this.findCodeInfoByCodeValueAndCodeType(rule, "codeInfoRules");
		if (codeInfo == null) {
			throw new ServiceException("系统中不存在码值规则【" + rule + "】");
		}
		// 制造出码值
		BatchMaker<SysCodeInfoVO> maker = batchObjectFactory.getMaker(rule, codeInfo.getExt1());
		List<SysCodeInfoVO> codeInfos = maker.text(text).make();
		
		if (ListUtils.isNotEmpty(codeInfos)) {
			int orderNumber = this.findMaxOrderNumber(typeId);
			for (SysCodeInfoVO code: codeInfos) {
				code.setOrderNumber(++orderNumber);
				// 绑定codeType
				SysCodeTypeVO codeType = new SysCodeTypeVO();
				codeType.setCodeTypeId(typeId);
				code.setCodeType(codeType);
				code.setState(1);
				this.saveCodeInfo(code);
			}
		}
	}

	@Override
	public Integer findMaxOrderNumber(String codeType) {
		if (StringUtils.isBlank(codeType)) {
			throw new ServiceException("codeType is null!");
		}
		Integer maxOrderNumber = codeInfoMapper.findMaxOrderNumber(codeType);
		if (maxOrderNumber == null) {
			return 0;
		}
		return maxOrderNumber;
	}
	
	@Override
	public String batchQuickAdd(String text) {
		if (StringUtils.isBlank(text)) {
			throw new ServiceException("保存失败，text内容为空！");
		}
		String[] codeArr = text.split("\n\n");
		if (codeArr == null || codeArr.length == 0) {
			return "没有数据";
		}
		
		int countAddType = 0;
		int countUpdateType = 0;
		int countAddInfo = 0;
		int countUpdateInfo = 0;
		
		for (String code: codeArr) {
			SysCodeTypeVO codeType = this.getCodeType(code);
			if (codeType == null) {
				continue;
			}
			// 查询数据库，若存在codeTypeId则更新，若不存在，则新增
			SysCodeTypeVO ct = codeTypeService.findCodeTypeById(codeType.getCodeTypeId());
			if (ct == null) {
				countAddType++; // 统计新增的码值类型
				codeTypeService.addOne(codeType);
			} else {
				countUpdateType++; // 统计更新的码值类型
				codeTypeService.updateOne(codeType);
			}
			
			// 新增或更新码值
			Set<SysCodeInfoVO> codeInfos = codeType.getCodeInfos();
			if (codeInfos == null || codeInfos.size() == 0) {
				continue;
			}
			for (SysCodeInfoVO ci: codeInfos) {
				ci.setCodeType(codeType);
				SysCodeInfoVO tci = this.findCodeInfoByCodeValueAndCodeType(ci.getCodeInfoValue(), codeType.getCodeTypeId());
				if (tci == null) {
					countAddInfo++; // 统计新增码值信息
					ci.setId(StringUtils.uuid());
					this.addOne(ci);
				} else {
					countUpdateInfo++; // 统计更新码值信息
					ci.setId(tci.getId());
					this.updateOne(ci);
				}
			}
		}
		
		StringBuilder sb = new StringBuilder();
		sb.append("码值类型新增数量: ")
			.append(countAddType)
			.append(", 码值类型更新数量: ")
			.append(countUpdateType)
			.append(", 码值新增数量: ")
			.append(countAddInfo)
			.append(", 码值更新数量:")
			.append(countUpdateInfo);
		
		return sb.toString();
	}
	
	private SysCodeTypeVO getCodeType(String code) {
		String[] comCodeArr = code.split("\n");
		if (comCodeArr == null || comCodeArr.length == 0) {
			return null;
		}
		
		SysCodeTypeVO codeType = new SysCodeTypeVO();
		for (int i = 0; i < comCodeArr.length; i ++) {
			String mcode = comCodeArr[i];
			if (i == 0) {
				// codeType
				String codeTypeName = StringUtils.regMatch(mcode, "name: ([^(,+})]*)");
				String codeTypeId = StringUtils.regMatch(mcode, "type: ([^(,+})]*)");
				if (StringUtils.isBlank(codeTypeId) || StringUtils.isBlank(codeTypeName)) {
					continue;
				}
				codeType.setCodeTypeId(codeTypeId);
				codeType.setCodeTypeName(codeTypeName);
				codeType.setState(1);
			} else {
				// codeInfo
				String codeInfoName = StringUtils.regMatch(mcode, "name: ([^(,+})]*)");
				String codeInfoValue = StringUtils.regMatch(mcode, "value: ([^(,+})]*)");
				String ext = StringUtils.regMatch(mcode, "ext: ([^(,+})]*)");
				
				if (StringUtils.isBlank(codeInfoValue) || StringUtils.isBlank(codeInfoName)) {
					continue;
				}
				
				SysCodeInfoVO codeInfo = new SysCodeInfoVO();
				codeInfo.setCodeInfoName(codeInfoName);
				codeInfo.setCodeInfoValue(codeInfoValue);
				codeInfo.setState(1);
				codeInfo.setExt1(ext);
				codeType.getCodeInfos().add(codeInfo);
			}
		}
		return codeType;
	}
	
}
